"""
教师端工具函数模块

提供教师端路由所需的通用功能，包括：
1. 装饰器：
   - teacher_required: 教师权限验证
   - handle_errors: 统一错误处理
2. 公共函数：
   - get_common_data: 获取通用数据（学院、班级、课程等）
   - get_paginated_results: 处理分页查询结果
"""

from flask import jsonify, current_app
from functools import wraps
from flask_login import current_user
from ..models.database import db
from ..models.models import College, Class, Course, Grade, Teacher, Student

# ==================== 装饰器 ====================
def teacher_required(f):
    """
    教师权限验证装饰器
    
    用于保护需要教师权限的API路由。该装饰器会：
    1. 检查用户是否已登录
    2. 验证用户是否为教师身份
    3. 如果验证失败，返回相应的错误响应
    
    Args:
        f (function): 需要装饰的API路由函数
        
    Returns:
        function: 装饰后的函数，增加了教师权限验证
        
    Example:
        @bp.route('/api/teacher/data')
        @teacher_required
        def get_data():
            return jsonify({'data': '教师数据'})
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated:
            return jsonify({'error': '请先登录'}), 401
        if not isinstance(current_user, Teacher):
            return jsonify({'error': '需要教师权限'}), 403
        return f(*args, **kwargs)
    return decorated_function

def handle_errors(f):
    """
    错误处理装饰器
    
    统一处理API路由中可能出现的错误，包括：
    1. 验证错误（ValueError, KeyError）
    2. 未预期的错误（Exception）
    
    该装饰器会：
    1. 捕获并记录错误信息
    2. 返回适当的错误响应
    3. 确保错误信息被正确记录到日志
    
    Args:
        f (function): 需要装饰的API路由函数
        
    Returns:
        function: 装饰后的函数，增加了错误处理
        
    Example:
        @bp.route('/api/teacher/action')
        @handle_errors
        def perform_action():
            # 可能抛出异常的代码
            return jsonify({'success': True})
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except (ValueError, KeyError) as e:
            current_app.logger.error(f'Validation error: {str(e)}')
            return jsonify({'error': str(e)}), 400
        except Exception as e:
            current_app.logger.error(f'Unexpected error: {str(e)}')
            return jsonify({'error': 'An unexpected error occurred'}), 500
    return decorated_function

# ==================== 公共函数 ====================
def get_common_data():
    """
    获取通用数据
    
    收集教师端页面常用的数据，包括：
    1. 学院列表
    2. 班级列表
    3. 课程列表
    4. 学期列表
    5. 当前教师信息和统计数据
    
    统计数据包括：
    - 负责班级数：教师所在学院的班级总数
    - 教授课程数：教师所在学院的课程总数
    - 学生总数：教师所在学院的学生总数
    - 成绩记录数：教师所在学院的成绩记录总数
    
    Returns:
        dict: 包含所有通用数据的字典，结构如下：
        {
            'colleges': [{'college_id': int, 'college_name': str}, ...],
            'classes': [{'class_id': int, 'class_name': str, 'college_id': int}, ...],
            'courses': [{'course_id': int, 'course_name': str, 'college_id': int}, ...],
            'semesters': [str, ...],
            'profile': {
                'teacher_id': int,
                'name': str,
                'college_id': int,
                'college_name': str,
                'total': {
                    'classes': int,
                    'courses': int,
                    'students': int,
                    'grades': int
                }
            }
        }
    """
    # 获取所有学院
    colleges = db.session.query(College.college_id, College.college_name).all()
    colleges = [{'college_id': c[0], 'college_name': c[1]} for c in colleges]
    
    # 获取所有班级
    classes = db.session.query(Class.class_id, Class.class_name, Class.college_id).all()
    classes = [{'class_id': c[0], 'class_name': c[1], 'college_id': c[2]} for c in classes]
    
    # 获取所有课程
    courses = db.session.query(Course.course_id, Course.course_name, Course.college_id).all()
    courses = [{'course_id': c[0], 'course_name': c[1], 'college_id': c[2]} for c in courses]
    
    # 获取所有学期
    semesters = db.session.query(Grade.semester).distinct().order_by(Grade.semester).all()
    semesters = [s[0] for s in semesters]
    
    # 获取当前教师信息和统计数据
    profile = None
    if current_user.is_authenticated:
        teacher = Teacher.query.get(current_user.teacher_id)
        if teacher:
            # 负责班级：教师所在学院的班级个数
            total_classes = db.session.query(Class).filter_by(college_id=teacher.college_id).count() or 0
            
            # 教授课程：成绩表中教师所在学院的课程数量
            total_courses = db.session.query(Grade.course_id)\
                .join(Course, Grade.course_id == Course.course_id)\
                .filter(Course.college_id == teacher.college_id)\
                .distinct()\
                .count() or 0
            
            # 学生总数：教师所在学院的所有班级的学生人数
            total_students = db.session.query(Student)\
                .join(Class, Student.class_id == Class.class_id)\
                .filter(Class.college_id == teacher.college_id)\
                .count() or 0
            
            # 录入成绩：教师所在学院的课程的所有成绩
            total_grades = db.session.query(Grade)\
                .join(Course, Grade.course_id == Course.course_id)\
                .filter(Course.college_id == teacher.college_id)\
                .count() or 0
            
            profile = {
                'teacher_id': teacher.teacher_id,
                'name': teacher.name,
                'college_id': teacher.college_id,
                'college_name': teacher.college.college_name if teacher.college else None,
                'total': {
                    'classes': int(total_classes),
                    'courses': int(total_courses),
                    'students': int(total_students),
                    'grades': int(total_grades)
                }
            }
    
    return {
        'colleges': colleges,
        'classes': classes,
        'courses': courses,
        'semesters': semesters,
        'profile': profile
    }

def get_paginated_results(query, page=1, per_page=20):
    """
    获取分页结果
    
    处理数据库查询的分页结果，支持：
    1. 单表查询
    2. 多表联合查询
    3. 自定义查询结果
    
    该函数会：
    1. 执行分页查询
    2. 处理查询结果（包括联合查询）
    3. 转换为统一的返回格式
    
    Args:
        query (Query): SQLAlchemy查询对象
        page (int): 当前页码，默认为1
        per_page (int): 每页记录数，默认为20
        
    Returns:
        dict: 包含分页结果的字典，结构如下：
        {
            'items': [
                # 单表查询
                {'field1': value1, 'field2': value2, ...},
                # 或联合查询
                {'field1': value1, 'extra_field': value2, ...},
                ...
            ],
            'pagination': {
                'total': int,      # 总记录数
                'pages': int,      # 总页数
                'current_page': int,  # 当前页码
                'has_next': bool,  # 是否有下一页
                'has_prev': bool   # 是否有上一页
            }
        }
        
    Note:
        - 查询结果中的对象如果有to_dict方法，会调用该方法转换为字典
        - 联合查询的结果会被合并到同一个字典中
        - 对于无法转换为字典的对象，会使用str()函数转换为字符串
    """
    pagination = query.paginate(page=page, per_page=per_page, error_out=False)
    # 处理查询结果
    items = []
    for item in pagination.items:
        if isinstance(item, tuple):
            # 如果是元组（联合查询的结果）
            if len(item) == 2:  # 两个表的联合查询
                main_obj, extra_field = item
                if hasattr(main_obj, 'to_dict'):
                    data = main_obj.to_dict()
                    # 添加额外字段
                    if isinstance(extra_field, str):
                        data['extra_field'] = extra_field
                    else:
                        data.update(extra_field.to_dict() if hasattr(extra_field, 'to_dict') else {'extra_field': str(extra_field)})
                else:
                    data = {'main': str(main_obj), 'extra': str(extra_field)}
            else:  # 多个表的联合查询
                data = {}
                for i, obj in enumerate(item):
                    if hasattr(obj, 'to_dict'):
                        data.update(obj.to_dict())
                    else:
                        data[f'field_{i}'] = str(obj)
        else:
            # 单个对象的查询
            data = item.to_dict() if hasattr(item, 'to_dict') else {'data': str(item)}
        items.append(data)
    
    return {
        'items': items,
        'pagination': {
            'total': pagination.total,
            'pages': pagination.pages,
            'current_page': pagination.page,
            'has_next': pagination.has_next,
            'has_prev': pagination.has_prev
        }
    } 